package javaframework;


import java.awt.Graphics;
import java.awt.Graphics2D;
import java.awt.event.ComponentEvent;
import java.awt.event.ComponentListener;
import java.awt.event.FocusEvent;
import java.awt.event.FocusListener;
import java.awt.event.KeyEvent;
import java.awt.event.KeyListener;
import java.util.Timer;
import java.util.TimerTask;

import javax.swing.JFrame;
import javax.swing.JPanel;
import javax.swing.WindowConstants;

import framework.GameContext;
import framework.GraphicsWrapper;
import framework.KInput;
import framework.ResourcesWrapper;
import framework.Screen;

@SuppressWarnings("serial")
public abstract class JavaGameContext extends JFrame implements GameContext {
	private static final int FPS = 60;
	private static final int LOWEST_FPS = 20;
	private static final int LONGEST_FRAME_TIME = 1000 / LOWEST_FPS;
	private final JPanel my_canvas;
	private Screen my_screen;
	private JavaGraphics my_graphics;
	private JavaInput my_input;
	private final JavaResources my_resources;
	private Timer my_timer;
	private TimerTask my_task;
	
	private final int[] my_hardWareKeys;
	private final int[] my_keys;
	private final String[] my_keyNames;
	
	public JavaGameContext(final String the_imagePath, final String[] the_keyNames, final int[] the_hardWareKeys, final int[] the_keys) {
		my_hardWareKeys = the_hardWareKeys;
		my_keys = the_keys;
		my_keyNames = the_keyNames;
		my_resources = new JavaResources(the_imagePath);
		my_graphics = new JavaGraphics();
		my_input = new JavaInput();
		my_screen = getInitialScreen();
		my_canvas = new JPanel(){
			public void paint(Graphics g) {
				Graphics2D g2 = (Graphics2D) g;
				my_graphics.setGraphics(g2);
			    my_screen.render();
			}
		};
		add(my_canvas);
		setDefaultCloseOperation(WindowConstants.EXIT_ON_CLOSE);
		setSize(256, 435);
//		setSize(524, 839);
		setTitle("Game Context");
		setLocationRelativeTo(null);
		setVisible(true);
		my_canvas.addMouseListener(my_input);
		my_canvas.addMouseMotionListener(my_input);
		
		this.addKeyListener(new KeyListener() {

			@Override
			public void keyPressed(KeyEvent e) {
				int code = getKeyCode(e.getKeyCode());
				if (code >= 0) {
					my_screen.keyPressed(code);
				}
			}

			@Override
			public void keyReleased(KeyEvent e) {
				int code = getKeyCode(e.getKeyCode());
				if (code >= 0) {
					my_screen.keyReleased(code);
				}
			}

			@Override
			public void keyTyped(KeyEvent e) {
				
			}
			
		});
		this.addFocusListener(new FocusListener() {

			@Override
			public void focusGained(FocusEvent e) {
				//my_canvas.focusGained(e); TODO
			}

			@Override
			public void focusLost(FocusEvent arg0) {
				//my_canvas.focusLost(arg0); TODO
			}
			
		});
		addComponentListener(new ComponentListener() {
			
			@Override
			public void componentShown(ComponentEvent e) {}
			
			@Override
			public void componentResized(ComponentEvent e) {
				System.out.println(getWidth() + " " + getHeight());
				my_graphics.resize(my_canvas.getWidth(), my_canvas.getHeight());
			}
			
			@Override
			public void componentMoved(ComponentEvent e) {}
			
			@Override
			public void componentHidden(ComponentEvent arg0) {}
		});
		
		my_timer = new Timer();
		setFPS(FPS);
		
			
	}
	private int getKeyCode(int the_key) {
		for (int i = 0; i < my_hardWareKeys.length; i++) {
			if (the_key == my_hardWareKeys[i]) {
				return my_keys[i];
			}
		}
		return -1;
	}
	public void setFPS(int FPS) {
		if (my_task != null) {
			my_task.cancel();
		}
		my_task = new TimerTask() {
			/**
			 * Used for measuring how long since the last step.
			 */
			private long my_lastUpdateTime = System.currentTimeMillis();
			
			public void run() {
				final long time = System.currentTimeMillis();
				int timeDelta = (int) (time - my_lastUpdateTime);
				if (timeDelta >= LONGEST_FRAME_TIME) {
					timeDelta = LONGEST_FRAME_TIME;
				}
				my_screen.step(timeDelta);
				
				
				my_lastUpdateTime = time;
				repaint();
			}
		};
		my_timer.schedule(my_task, 300, 1000 / FPS);	
	}
	
	@Override
	public GraphicsWrapper getGraphicsWrapper() {
		return my_graphics;
	}
	
	@Override
	public KInput getInput() {
		return my_input;
	}
	
	@Override
	public ResourcesWrapper getResourcesWrapper() {
		return my_resources;
	}


	@Override
	public void setScreen(final Screen the_screen) {
		my_screen = the_screen;
		
	}

	@Override
	public Screen getCurrentScreen() {
		return my_screen;
	}

}
